#pragma once
#include "../tcp_server_v2.hpp"
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>

#include <regex>

using namespace std;

unordered_map<int, string> _state_msg = {
    {100,  "Continue"},
    {101,  "Switching Protocol"},
    {102,  "Processing"},
    {103,  "Early Hints"},
    {200,  "OK"},
    {201,  "Created"},
    {202,  "Accepted"},
    {203,  "Non-Authoritative Information"},
    {204,  "No Content"},
    {205,  "Reset Content"},
    {206,  "Partial Content"},
    {207,  "Multi-Status"},
    {208,  "Already Reported"},
    {226,  "IM Used"},
    {300,  "Multiple Choice"},
    {301,  "Moved Permanently"},
    {302,  "Found"},
    {303,  "See Other"},
    {304,  "Not Modified"},
    {305,  "Use Proxy"},
    {306,  "unused"},
    {307,  "Temporary Redirect"},
    {308,  "Permanent Redirect"},
    {400,  "Bad Request"},
    {401,  "Unauthorized"},
    {402,  "Payment Required"},
    {403,  "Forbidden"},
    {404,  "Not Found"},
    {405,  "Method Not Allowed"},
    {406,  "Not Acceptable"},
    {407,  "Proxy Authentication Required"},
    {408,  "Request Timeout"},
    {409,  "Conflict"},
    {410,  "Gone"},
    {411,  "Length Required"},
    {412,  "Precondition Failed"},
    {413,  "Payload Too Large"},
    {414,  "URI Too Long"},
    {415,  "Unsupported Media Type"},
    {416,  "Range Not Satisfiable"},
    {417,  "Expectation Failed"},
    {418,  "I'm a teapot"},
    {421,  "Misdirected Request"},
    {422,  "Unprocessable Entity"},
    {423,  "Locked"},
    {424,  "Failed Dependency"},
    {425,  "Too Early"},
    {426,  "Upgrade Required"},
    {428,  "Precondition Required"},
    {429,  "Too Many Requests"},
    {431,  "Request Header Fields Too Large"},
    {451,  "Unavailable For Legal Reasons"},
    {501,  "Not Implemented"},
    {502,  "Bad Gateway"},
    {503,  "Service Unavailable"},
    {504,  "Gateway Timeout"},
    {505,  "HTTP Version Not Supported"},
    {506,  "Variant Also Negotiates"},
    {507,  "Insufficient Storage"},
    {508,  "Loop Detected"},
    {510,  "Not Extended"},
    {511,  "Network Authentication Required"}
};

unordered_map<string, string> _mime_msg = {
    {".aac",        "audio/aac"},
    {".abw",        "application/x-abiword"},
    {".arc",        "application/x-freearc"},
    {".avi",        "video/x-msvideo"},
    {".azw",        "application/vnd.amazon.ebook"},
    {".bin",        "application/octet-stream"},
    {".bmp",        "image/bmp"},
    {".bz",         "application/x-bzip"},
    {".bz2",        "application/x-bzip2"},
    {".csh",        "application/x-csh"},
    {".css",        "text/css"},
    {".csv",        "text/csv"},
    {".doc",        "application/msword"},
    {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
    {".eot",        "application/vnd.ms-fontobject"},
    {".epub",       "application/epub+zip"},
    {".gif",        "image/gif"},
    {".htm",        "text/html"},
    {".html",       "text/html"},
    {".ico",        "image/vnd.microsoft.icon"},
    {".ics",        "text/calendar"},
    {".jar",        "application/java-archive"},
    {".jpeg",       "image/jpeg"},
    {".jpg",        "image/jpeg"},
    {".js",         "text/javascript"},
    {".json",       "application/json"},
    {".jsonld",     "application/ld+json"},
    {".mid",        "audio/midi"},
    {".midi",       "audio/x-midi"},
    {".mjs",        "text/javascript"},
    {".mp3",        "audio/mpeg"},
    {".mpeg",       "video/mpeg"},
    {".mpkg",       "application/vnd.apple.installer+xml"},
    {".odp",        "application/vnd.oasis.opendocument.presentation"},
    {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
    {".odt",        "application/vnd.oasis.opendocument.text"},
    {".oga",        "audio/ogg"},
    {".ogv",        "video/ogg"},
    {".ogx",        "application/ogg"},
    {".otf",        "font/otf"},
    {".png",        "image/png"},
    {".pdf",        "application/pdf"},
    {".ppt",        "application/vnd.ms-powerpoint"},
    {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
    {".rar",        "application/x-rar-compressed"},
    {".rtf",        "application/rtf"},
    {".sh",         "application/x-sh"},
    {".svg",        "image/svg+xml"},
    {".swf",        "application/x-shockwave-flash"},
    {".tar",        "application/x-tar"},
    {".tif",        "image/tiff"},
    {".tiff",       "image/tiff"},
    {".ttf",        "font/ttf"},
    {".txt",        "text/plain"},
    {".vsd",        "application/vnd.visio"},
    {".wav",        "audio/wav"},
    {".weba",       "audio/webm"},
    {".webm",       "video/webm"},
    {".webp",       "image/webp"},
    {".woff",       "font/woff"},
    {".woff2",      "font/woff2"},
    {".xhtml",      "application/xhtml+xml"},
    {".xls",        "application/vnd.ms-excel"},
    {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
    {".xml",        "application/xml"},
    {".xul",        "application/vnd.mozilla.xul+xml"},
    {".zip",        "application/zip"},
    {".3gp",        "video/3gpp"},
    {".3g2",        "video/3gpp2"},
    {".7z",         "application/x-7z-compressed"}
};

class Ultil {
public:
    // 分割字符串
    static vector<string> split_str(const string &s, const string &sep) {
        vector<string> arr;
        for(size_t prev = 0, cur = s.find(sep, 0); true; prev = cur + sep.size(), cur = s.find(sep, prev)) {
            string sub = s.substr(prev, cur - prev);
            if(!sub.empty()) {
                arr.push_back(move(sub));
            }
            if(cur >= s.size()) {
                break;
            }
        }
        return arr;
    }
    
    // 读取文本文件
    static bool read_file(const string &filename, string *buf) {
        ifstream ifs(filename, ios::binary);
        if(!ifs.is_open()) {
            ERROR_LOG("Can't open file %s", filename.c_str());
            return false;
        }
        ifs.seekg(0, ios::end);
        int length = ifs.tellg();
        ifs.seekg(0, ios::beg);

        buf->resize(length);
        ifs.read((char*)buf->c_str(), length);
        ifs.close();
        return true;
    }

    // 向文本文件写入
    static bool write_file(const string &filename, const string &buf) {
        ofstream ofs(filename, ios::trunc);
        if(!ofs.is_open()) {
            ERROR_LOG("Can't open file %s", filename.c_str());
            return false;
        }
        ofs << buf;
        ofs.close();
        return true;
    }      

    // URL编码
    // 避免url中资源路径与查询字符串中的特殊字符与HTTP请求中的特殊字符产生歧义
    // 在RFC3986文档中规定的编码格式：将特殊字符的ascii码值转换为一个百分号带上两位16进制字符
    // 但是存在一些特殊不编码字符，同样在RFC3986文档中规定 . - _ ~ 字母 数字 这些字符为绝对不编码字符
    // W3C标准规定，查询字符串中的空格需要编码为加号，解码则是再换回空格
    static string url_encode(const string &url, bool convert_space_to_plus) {
        string res;
        for (char c : url) {
            if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
                res += c;
            } 
            else if(c == ' ' && convert_space_to_plus) {
                res += '+'; 
            }
            else {
                char temp[4] = {0};
                snprintf(temp, sizeof(temp), "%%%02X", c);
                res += temp;
            }
        }
        return res;
    }

    static char hex_to_char(char c) {
        if(c >= '0' && c <= '9') {
            return c - '0';
        }
        else if(c >= 'A' && c <= 'F') {
            return c - 'A' + 10;
        }
        else if(c >= 'a' && c <= 'f') {
            return c - 'a' + 10;
        }
        return 0;
    }
    static string url_decode(const string &url, bool convert_plus_to_space) {
        string res;
        for (int i = 0; i < url.length(); ++i) {
            char c = url[i];
            if (c == '%') {
                if(i + 2 < url.length()) {
                    char n1 = hex_to_char(url[++i]);
                    char n2 = hex_to_char(url[++i]);
                    res += (n1 << 4) + n2;
                }
                else {
                    res += '%'; // 非法URL，解码出来的结果中会有%字符
                    ERROR_LOG("invalid url: %s", url.c_str());
                }
            } 
            else if(c == '+' && convert_plus_to_space) {
                res +=' ';
            }
            else {
                res += c;
            }
        }
        return res;
    }

    //响应状态码的描述信息获取
    static string states_string(int resp_code) {
        auto it = _state_msg.find(resp_code);
        if (it != _state_msg.end()) {
            return it->second;
        }
        return "Unknow";
    }

    //根据文件后缀名获取文件mime
    static string ex_mime(const string &filename) {
        
        // a.b.txt  先获取文件扩展名
        size_t pos = filename.find_last_of('.');
        if (pos == string::npos) {
            return "application/octet-stream";
        }
        //根据扩展名，获取mime
        string ext = filename.substr(pos);
        auto it = _mime_msg.find(ext);
        if (it == _mime_msg.end()) {
            return "application/octet-stream";
        }
        return it->second;
    }

    //判断一个文件是否是一个目录
    static bool is_directory(const string &filename) {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0) {
            return false;
        }
        return S_ISDIR(st.st_mode);
    }

    //判断一个文件是否是一个普通文件
    static bool is_regular(const string &filename) {
        struct stat st;
        int ret = stat(filename.c_str(), &st);
        if (ret < 0) {
            ERROR_LOG("file %s not found", filename.c_str());
            return false;
        }
        return S_ISREG(st.st_mode);
    }

    // 判断一个资源路径是否有效
    // 假设要获取的资源路径为/index.html，其中/为网页根目录或者叫做相对根目录，也就是服务器中的某个子目录
    // index.html为这个目录下的资源文件，一个有效的资源路径必须要保证获取的资源文件是在网页根目录中
    // 不可以让客户端访问这个根目录父目录，为的是保证服务器资源的安全性和保密性
    // 所以要对对资源路径进行判断
    static bool is_valid_resource_path(const string &resource_path) {
        // 根据/对路径进行分割，然后判断路径深度
        // 初始化深度为0，若遇到..则--，否则++，若减到负数则说明跑到了网页根目录的上级目录去了，这是不合法的
        vector<string> dirs = split_str(resource_path, "/");
        int depth = 0;
        for(const auto &dir : dirs) {
            depth += (dir == ".." ? -1 : 1);
            if(depth < 0) {
                return false;
            }
        }
        return true;
    }
};

class http_request {
public:
    http_request():_version("HTTP/1.1") 
    {}

    // 避免上次处理结果对这次造成影响
    void reset() {
        _method.clear();
        _path.clear();
        _version = "HTTP/1.1";
        _context.clear();
        smatch match;
        _matches.swap(match);
        _headers.clear();
        _params.clear();
    }

    //插入头部字段
    void set_header(const string &key, const string &val) {
        _headers.insert(make_pair(key, val));
    }

    //判断是否存在指定头部字段
    bool has_header(const string &key) const {
        auto it = _headers.find(key);
        if (it == _headers.end()) {
            return false;
        }
        return true;
    }

    //获取指定头部字段的值
    string get_header(const string &key) const {
        auto it = _headers.find(key);
        if (it == _headers.end()) {
            return "";
        }
        return it->second;
    }

    //插入查询字符串
    void set_param(const string &key, const string &val) {
        _params.insert(make_pair(key, val));
    }

    //判断是否有某个指定的查询字符串
    bool has_param(const string &key) const {
        auto it = _params.find(key);
        if (it == _params.end()) {
            return false;
        }
        return true;
    }

    //获取指定的查询字符串
    string get_param(const string &key) const {
        auto it = _params.find(key);
        if (it == _params.end()) {
            return "";
        }
        return it->second;
    }

    //获取正文长度
    size_t content_length() const {
        // Content-Length: 1234\r\n
        bool ret = has_header("Content-Length");
        if (!ret) {
            return 0;
        }
        string clen = get_header("Content-Length");
        return stol(clen);
    }
    //判断是否是短链接
    bool close() const {
        // 没有Connection字段，或者有Connection但是值是close，则都是短链接，否则就是长连接
        if (has_header("Connection") && get_header("Connection") == "keep-alive") {
            return false;
        }
        return true;
    }
public:
    string _method;  // 请求方法
    string _path;    // 资源路径
    string _version; // 协议版本
    string _context;    // 请求正文
    smatch _matches;  // 通过正则库提取资源路径中的数据进行保存
    unordered_map<string, string> _headers;// 头部字段
    unordered_map<string, string> _params; // 查询字符串
};

class http_response {
public:
    http_response(int resp_code = 200):_redirect_flag(false), _resp_code(resp_code) 
    {} 
    
    void reset() {
        _resp_code = 200;
        _redirect_flag = false;
        _context.clear();
        _redirect_url.clear();
        _headers.clear();
    }

    //插入头部字段
    void set_header(const string &key, const string &val) {
        _headers.insert(make_pair(key, val));
    }

    //判断是否存在指定头部字段
    bool has_header(const string &key) const {
        auto it = _headers.find(key);
        if (it == _headers.end()) {
            return false;
        }
        return true;
    }

    //获取指定头部字段的值
    string get_header(const string &key) const {
        auto it = _headers.find(key);
        if (it == _headers.end()) {
            return "";
        }
        return it->second;
    }

    void set_context(const string &context,  const string &type = "text/html") {
        _context = context;
        set_header("Content-Type", type);
    }

    void set_redirect(const string &url, int resp_code = 302) {
        _resp_code = resp_code;
        _redirect_flag = true;
        _redirect_url = url;
    }

    //判断是否是短链接
    bool close() {
        // 没有Connection字段，或者有Connection但是值是close，则都是短链接，否则就是长连接
        if (has_header("Connection") && get_header("Connection") == "keep-alive") {
            return false;
        }
        return true;
    }
public:
    int _resp_code;
    bool _redirect_flag;
    string _context;
    string _redirect_url;
    unordered_map<string, string> _headers;
};

enum recv_state {
    RECV_ERROR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_CONTEXT,
    RECV_HTTP_END
};

// http首部长度最大一般设置为8k
#define MAX_LINE_LENGTH 8192

class context {
private:
    int _resp_code; // 响应状态码
    recv_state _recv_state; // 当前接收请求的状态
    http_request _req;  // 已经得到的请求信息
public:
    context() :_recv_state(RECV_HTTP_LINE), _resp_code(200)
    {}

    void reset() {
        _resp_code = 200;
        _recv_state = RECV_HTTP_LINE;
        _req.reset();
    }
    
    recv_state get_recv_state() const {
        return _recv_state;
    }

    int get_resp_code() const {
        return _resp_code;
    }

    http_request &get_req() {
        return _req;
    }

    void handle_http_request(buffer *buf) {
        switch(_recv_state) {
            case RECV_HTTP_LINE: get_http_line(buf);
            case RECV_HTTP_HEAD: get_http_headers(buf); 
            case RECV_HTTP_CONTEXT: get_http_context(buf);
        }
    }

private:
    string get_line(buffer *buf) {
        string line = buf->find_line();
        if(line.empty()) {
            // 到这里说明不足一行
            // 此时需要检查一下缓冲区中的数据长度，如果很长都不足一行那认为这个请求是有问题的
            // 直接返回并设置响应状态码
            if(buf->get_readable_size() > MAX_LINE_LENGTH) {
                _recv_state = RECV_ERROR;
                // "URI Too Long"
                _resp_code = 414;
                ERROR_LOG("URI Too Long");
            }   
            // 否则需要继续等待新数据的到来
            return "";
        }
        // 同样的道理，如果一行太长了
        if(line.size() > MAX_LINE_LENGTH) {
            _recv_state = RECV_ERROR;
            // "URI Too Long"
            _resp_code = 414;
            ERROR_LOG("URI Too Long");
            return "";
        }
        return line;
    }

    bool get_http_line(buffer *buf) {
        if(_recv_state != RECV_HTTP_LINE) {
            ERROR_LOG("err _recv_state != RECV_HTTP_LINE");
            return false;
        }
        string line = get_line(buf);
        if(line.empty()) {
            return false;
        }
        // 解析HTTP请求行
        bool ret = handle_line(line);
        if(!ret) {
            ERROR_LOG("Handle Line Failed");
            return false;
        }
        _recv_state = RECV_HTTP_HEAD;
        return true;
    }

    bool handle_line(const string &line) {
        smatch matches;
        // 忽略大小写
        regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.\\d)(?:\n|\r\n)?", regex::icase);
        bool ret = regex_match(line, matches, e);
        if (!ret) {
            ERROR_LOG("Regex Match failed");
            return false;
        }
        // 请求方法
        _req._method = matches[1];
        // 转大写
        transform(_req._method.begin(), _req._method.end(), _req._method.begin(), ::toupper);
        // 需要注意的是在资源路径中，有些特殊字符是被编码过的，因此需要进行解码再保存
        // 不需要加号转空格
        _req._path = Ultil::url_decode(matches[2], false);
        // 请求版本
        _req._version = matches[4];
        // 先按照&分割出各个查询字符串，格式为key=val，然后继续分割并解码->key, val进行保存
        vector<string> query_str = Ultil::split_str(matches[3], "&");
        for(auto &str : query_str) {
            size_t pos = str.find('=');
            if(pos == string::npos) {
                _recv_state = RECV_ERROR;
                // "BAD Reqeust"
                _resp_code = 400;
                ERROR_LOG("BAD Reqeust");
                return false;
            }
            string k = Ultil::url_decode(str.substr(0, pos), true);
            // 加号转换成空格
            string v = Ultil::url_decode(str.substr(pos + 1), true);
            _req.set_param(k, v);
        }
        return true;
    }

    bool get_http_headers(buffer *buf) {
        if(_recv_state != RECV_HTTP_HEAD) {
            ERROR_LOG("err _recv_state != RECV_HTTP_HEAD");
            return false;
        }
        // 请求头部的格式为：key: val\r\n，且包含多个
        // 逐行取出即可
        while(true) {
            string line = get_line(buf);
            if(line.empty()) {
                return false;
            }
            // 遇到空行
            if(line == "\n" || line == "\r\n") {
                break;
            }
            // 分割头部
            bool ret = handle_headers(line);
            if(!ret) {
                ERROR_LOG("Handle Headers Failed");
                return false;
            }
        }
        _recv_state = RECV_HTTP_CONTEXT;
        return true;
    }

    bool handle_headers(string &line) {
        //末尾是换行则去掉换行字符
        if (line.back() == '\n') {
            line.pop_back();
        }
        if (line.back() == '\r') {
            line.pop_back();
        }
        size_t pos = line.find(": ");
        if(pos == string::npos) {
            _recv_state = RECV_ERROR;
            // "BAD Reqeust"
            _resp_code = 400;
            ERROR_LOG("BAD Reqeust");
            return false;
        }
        string k = line.substr(0, pos);
        string v = line.substr(pos + 2);
        _req.set_header(k, v);
        return true;
    } 

    bool get_http_context(buffer *buf) {
        if(_recv_state != RECV_HTTP_CONTEXT) {
            ERROR_LOG("err _recv_state != RECV_HTTP_CONTENT");
            return false;
        }
        // 获取正文长度
        size_t content_len = _req.content_length();
        if(content_len == 0) {
            // 没有正文，则请求解析结束
            _recv_state = RECV_HTTP_END;
            return true;
        }
        // 已经获取的正文长度保存在_req.context中，需要计算一下还需要多少数据才够content_len
        // 然后接收剩下的数据继续放入到content_len中
        size_t needed_len = content_len - _req._context.size();
        // 需要考虑的是，若缓冲区中的可读数据不足一条请求正文，这时需要把不足的数据取出来放入_req.context中
        // 等待下次数据的到来
        // 否则足够一条请求，那么同样取出来放入_req.context中然后进行处理
        size_t min_len = min(needed_len, (size_t)buf->get_readable_size());
        _req._context.append(buf->get_read_pos(), min_len);
        buf->move_read_pos(min_len);
        if(needed_len == min_len) {
            _recv_state = RECV_HTTP_END;
        }
        return true;
    }
};

class http_server {
    using functor = function<void(const http_request&, http_response*)>;
    using handler_t = vector<pair<regex, functor>>;
private:
    // 各种请求方法表
    handler_t _get_handler;
    handler_t _post_handler;
    handler_t _put_handler;
    handler_t _delete_handler;
    // 静态资源子目录
    string _base_static_dir;
    tcp_server _server;
private:
    // 设置上下文
    void handle_connected(const con_ptr &con) {
        con->set_context(context());
        DEBUG_LOG("new connection");
    }
    
    // 缓冲区数据解析+处理
    // 当套接字接收到数据之后调用
    void handle_messgae(const con_ptr &con, buffer *buf) {
        // 只要有数据就一直处理
        while(buf->get_readable_size() > 0) {
            // 获取上下文
            context *text = con->get_context()->get<context>();
            // 通过上下文对缓冲区数据进行解析，得到http_request对象
            text->handle_http_request(buf);
            http_request &req = text->get_req();
            http_response res(text->get_resp_code());
            // 解析是由可能出错的
            if(text->get_resp_code() >= 400) {
                // 进行错误响应，关闭连接
                handler_error(&res); // 填充错误页面到res中
                send_response(con, req, &res);
                text->reset();
                buf->move_read_pos(buf->get_readable_size());
                return;
            }
            // 只要解析完毕才能继续处理
            if(text->get_recv_state() != RECV_HTTP_END) {
                // 可能数据不够，等新数据到来再继续处理
                return;
            }
            // 通过请求路由+业务处理得到响应
            route(req, &res);
            // 组织发送响应
            send_response(con, req, &res);
            // 重置当前上下文
            text->reset();
            // 判断连接是否需要关闭
            if(res.close()) {
                con->shut_down();
            }
        }
    }

    // 错误处理
    void handler_error(http_response *res) {
        string body = "页面不存在...\n";
        res->set_context(body, "text/html");
    }


    void route(http_request& req, http_response *res) {
        // 需要对请求进行分辨，看看是哪种请求类型
        // 静态资源请求还是功能性请求
        // 默认GET\HEAD请求为静态资源请求
        // 如果都不是（功能性请求没有对应的处理函数）则返回405metho not allowed
        if(is_static_file(req)) {
            handle_static_file(req, res);
            return;
        }
        // 这里说明是功能性请求
        if (req._method == "GET" || req._method == "HEAD") {
            return dispatcher(req, res, _get_handler);
        }
        else if (req._method == "POST") {
            return dispatcher(req, res, _post_handler);
        }
        else if (req._method == "PUT") {
            return dispatcher(req, res, _put_handler);
        }
        else if (req._method == "DELETE") {
            return dispatcher(req, res, _delete_handler);
        }
        res->_resp_code = 405;
    }
    
    // 判断是否是静态资源
    bool is_static_file(const http_request& req) {
        // 若是静态资源，则必须要设置静态资源根目录
        if(_base_static_dir.empty()) {
            return false;
        }
        // 请求方法必须是GET和HEAD，用来获取资源的方法
        if(!(req._method == "GET" || req._method == "HEAD")) {
            return false;
        }
        // 请求资源路径必须是一个合法路径
        if(!Ultil::is_valid_resource_path(req._path)) {
            return false;
        }
        // 请求的资源必须存在,且是一个普通文件
        //  有一种请求比较特殊 -- 目录：/, /image/， 这种情况给后边默认追加一个 index.html
        // index.html    /image/a.png
        // 不要忘了前缀的相对根目录,也就是将请求路径转换为实际存在的路径  /image/a.png  ->   ./wwwroot/image/a.png
        string path = _base_static_dir + req._path;
        if(req._path.back() == '/') {
            path += "index.html";
        }
        if(!Ultil::is_regular(path)) {
            return false;
        }
        return true;
    }

    // 静态资源的处理
    void handle_static_file(const http_request& req, http_response *res) {
        string path = _base_static_dir + req._path;
        if (req._path.back() == '/')  {
            path += "index.html";
        }
        if(!Ultil::read_file(path, &res->_context)) {
            return;
        }
        string mime = Ultil::ex_mime(path);
        res->set_header("Content-Type", mime);
    }

    // 功能性请求的分类处理，根据请求的请求方法
    void dispatcher(http_request& req, http_response *res, const handler_t &handler) {
        //在对应请求方法的路由表中，查找是否含有对应资源请求的处理函数，有则调用，没有则返回404
        //思想：路由表存储的时键值对 -- 正则表达式 & 处理函数
        //使用正则表达式，对请求的资源路径进行正则匹配，匹配成功就使用对应函数进行处理
        //  /numbers/(\d+)       /numbers/12345
        for (const auto &handle : handler) {
            const regex &re = handle.first;
            const functor &func = handle.second;
            if (!regex_match(req._path, req._matches, re)) {
                continue;
            }
            func(req, res);//传入请求信息，和空的res，执行处理函数
            return;
        }
        res->_resp_code = 404;
    }

    // 将响应中的要素按照http响应的格式进行填充并发送
    void send_response(const con_ptr &con, const http_request& req, http_response *res) {
        // 先完善响应的头部字段
        // 根据请求设置长短连接
        if(req.close()) {
            res->set_header("Connection", "close");
        }
        else {
            res->set_header("Connection", "keep-alive");
        }
        // 如果有正文还需要设置正文长度和正文数据类型
        if(!res->_context.empty()) {
            res->set_header("Content-Length", to_string(res->_context.size()));
            res->set_header("Content-Type", "application/octet-stream");
        }
        // 如请求设置了重定向，则设置
        if(res->_redirect_flag) {
            res->set_header("Location", res->_redirect_url);
        }
        // 按照响应格式转换成字节流数据发送
        stringstream res_str;
        // 响应行
        res_str << req._version << " " << res->_resp_code << " " << Ultil::states_string(res->_resp_code) << "\r\n";
        // 响应头部
        for(const auto &headers : res->_headers) {
            res_str << headers.first << ": " << headers.second << "\r\n";
        }
        // 空行
        res_str << "\r\n";
        // 正文
        if(!res->_context.empty()) {
            res_str << res->_context;
        }
        con->send(res_str.str().c_str(), res_str.str().size());
    }
public:
    http_server(uint16_t port = 8080, int timeout = 5) :_server(port) {
        _server.enable_inactive_destroy(timeout);
        _server.set_connected_callback(bind(&http_server::handle_connected, this, placeholders::_1));
        _server.set_messge_callback(bind(&http_server::handle_messgae, this, placeholders::_1, placeholders::_2));
    }

    void set_base_static_dir(const string base_static_dir) {
        if(!Ultil::is_directory(base_static_dir)) {
            exit(-1);
        }
        _base_static_dir = base_static_dir;
    }

    void get(const string &pattern, const functor &handler) {
        _get_handler.emplace_back(regex(pattern), handler);
    }

    void post(const string &pattern, const functor &handler) {
        _post_handler.emplace_back(regex(pattern), handler);
    }

    void put(const string &pattern, const functor &handler) {
        _put_handler.emplace_back(regex(pattern), handler);
    }

    void del(const string &pattern, const functor &handler) {
        _delete_handler.emplace_back(regex(pattern), handler);
    }

    void set_thread_count(int count) {
        _server.set_thread_count(count);
    }

    void start() {
        _server.start();
    }
};